import java.io.File;
import java.lang.reflect.Method;

import org.budo.support.lang.util.IoUtil;
import org.budo.support.lang.util.ReflectUtil;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

// List & Array & Map 中包含需代理的对象
// Document 2 个
// DBObject 若干
// BasicDBObject BasicBSONObject LinkedHashMap 无
// BasicDBList BasicBSONList ArrayList 无
public class _Wrapper_ extends AbstractWrapper {
    public static void main(String[] args) {
        new _Wrapper_().go();
    }

    private void go() {
        go_MongoClient();

        go_DB();

        go_DBCollection();

        go_MongoDatabase();

        go_DBCursor();

        // go_DBObject();

        go_MongoCollection();

        IoUtil.write(abstractMongoFilter.toString(), new File("./src/main/java/org/budo/mongo/filter/AbstractMongoFilter.java"));
        IoUtil.write(mongoFilter.toString(), new File("./src/main/java/org/budo/mongo/filter/MongoFilter.java"));
        IoUtil.write(filterChain.toString(), new File("./src/main/java/org/budo/mongo/filter/MongoFilterChain.java"));
        IoUtil.write(filterChainImpl.toString(), new File("./src/main/java/org/budo/mongo/filter/MongoFilterChainImpl.java"));

        IoUtil.write(dbCollectionWrapper.toString(), new File("./src/main/java/org/budo/mongo/wrapper/DBCollectionWrapper.java"));
        IoUtil.write(dbWrapper.toString(), new File("./src/main/java/org/budo/mongo/wrapper/DBWrapper.java"));
        IoUtil.write(mongoClientWrapper.toString(), new File("./src/main/java/org/budo/mongo/wrapper/MongoClientWrapper.java"));
        IoUtil.write(mongoDatabaseWrapper.toString(), new File("./src/main/java/org/budo/mongo/wrapper/MongoDatabaseWrapper.java"));
        IoUtil.write(dbCursorWrapper.toString(), new File("./src/main/java/org/budo/mongo/wrapper/DBCursorWrapper.java"));
        IoUtil.write(mongoCollectionWrapper.toString(), new File("./src/main/java/org/budo/mongo/wrapper/MongoCollectionWrapper.java"));
        // IoUtil.write(dbObjectWrapper.toString(), new File("./src/main/java/org/budo/mongo/wrapper/DBObjectWrapper.java"));

        System.err.println("done");
    }

    protected void go_DBObject() {
        Method[] methods = ReflectUtil.getMethods_2(BasicDBObject.class); // BasicDBObject
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            dbObjectWrapper._import(method);

            filterChain._import(method);
            filterChainImpl._import(method);
            mongoFilter._import(method);
            abstractMongoFilter._import(method);

            dbObjectWrapper.append("    @Override\n");
            dbObjectWrapper.append("    public " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameters(method) + ") {\n");
            dbObjectWrapper.append("        " + _return(method) + "filterChain.dbObject_" + method.getName() + "(this.dbObject " + args_2(method) + ");\n");
            dbObjectWrapper.append("    }\n\n");

            // filterChain
            filterChain.append("    " + method.getReturnType().getSimpleName() + " dbObject_" + method.getName() + "(DBObject dbObject " + parameters_2(method) + ");\n\n");

            // mongoFilterChainImpl
            filterChainImpl.append("    @Override\n    ");
            filterChainImpl.append("    public synchronized " + method.getReturnType().getSimpleName() + " dbObject_" + method.getName() + "(DBObject dbObject " + parameters_2(method) + ") {\n");
            filterChainImpl.append("        if (this.position < this.getFilters().size()) {\r\n"); //
            filterChainImpl.append("            MongoFilter nextFilter = this.getFilters().get(this.position++);\n");
            filterChainImpl.append("            " + _return(method) + " nextFilter.dbObject_" + method.getName() + "(this, dbObject " + args_2(method) + ");\r\n"); //
            filterChainImpl.append("        } else { \n"); //
            filterChainImpl.append("            " + wrapperResult_2(method, "dbObject"));//
            filterChainImpl.append("        }\n");
            filterChainImpl.append("    }\n\n");

            // mongoFilter
            mongoFilter.append("    " + method.getReturnType().getSimpleName() + " dbObject_" + method.getName() + "(MongoFilterChain chain, DBObject dbObject " + parameters_2(method) + ");\n\n");

            // abstractMongoFilter
            abstractMongoFilter.append("    @Override\n");
            abstractMongoFilter.append("    public " + method.getReturnType().getSimpleName() + " dbObject_" + method.getName() + "(MongoFilterChain filterChain, DBObject dbObject " + parameters_2(method) + ") {\n");
            abstractMongoFilter.append("        " + _return(method) + "filterChain.dbObject_" + method.getName() + "(dbObject " + args_2(method) + ");\n");
            abstractMongoFilter.append("    }\n\n");
        }
    }

    private void go_MongoCollection() {
        Method[] methods = ReflectUtil.getMethods_2(MongoCollection.class);
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            mongoCollectionWrapper._import(method);

            filterChain._import(method);
            filterChainImpl._import(method);
            mongoFilter._import(method);
            abstractMongoFilter._import(method);

            mongoCollectionWrapper.append("    @Override\n");
            mongoCollectionWrapper.append("    public " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameters(method) + ") {\n");
            mongoCollectionWrapper.append("        " + _return(method) + "filterChain.mongoCollection_" + method.getName() + "(this.mongoCollection " + args_2(method) + ");\n");
            mongoCollectionWrapper.append("    }\n\n");

            // filterChain
            filterChain.append("    " + method.getReturnType().getSimpleName() + " mongoCollection_" + method.getName() + "(MongoCollection mongoCollection " + parameters_2(method) + ");\n\n");

            // mongoFilterChainImpl
            filterChainImpl.append("    @Override\n    ");
            filterChainImpl.append("    public synchronized " + method.getReturnType().getSimpleName() + " mongoCollection_" + method.getName() + "(MongoCollection mongoCollection " + parameters_2(method) + ") {\n");
            filterChainImpl.append("        if (this.position < this.getFilters().size()) {\r\n"); //
            filterChainImpl.append("            MongoFilter nextFilter = this.getFilters().get(this.position++);\n");
            filterChainImpl.append("            " + _return(method) + " nextFilter.mongoCollection_" + method.getName() + "(this, mongoCollection " + args_2(method) + ");\r\n"); //
            filterChainImpl.append("        } else { \n"); //
            filterChainImpl.append("            " + wrapperResult_2(method, "mongoCollection"));//
            filterChainImpl.append("        }\n");
            filterChainImpl.append("    }\n\n");

            // mongoFilter
            mongoFilter.append("    " + method.getReturnType().getSimpleName() + " mongoCollection_" + method.getName() + "(MongoFilterChain chain, MongoCollection mongoCollection " + parameters_2(method) + ");\n\n");

            // abstractMongoFilter
            abstractMongoFilter.append("    @Override\n");
            abstractMongoFilter.append("    public " + method.getReturnType().getSimpleName() + " mongoCollection_" + method.getName() + "(MongoFilterChain filterChain, MongoCollection mongoCollection " + parameters_2(method) + ") {\n");
            abstractMongoFilter.append("        " + _return(method) + "filterChain.mongoCollection_" + method.getName() + "(mongoCollection " + args_2(method) + ");\n");
            abstractMongoFilter.append("    }\n\n");
        }
    }

    private void go_DBCursor() {
        Method[] methods = ReflectUtil.getMethods_2(DBCursor.class);
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            if ("public java.lang.Object com.mongodb.DBCursor.next()".equals(method.toString())) {
                continue;
            }

            // dbWrapper
            dbCursorWrapper._import(method);

            filterChain._import(method);
            filterChainImpl._import(method);
            mongoFilter._import(method);
            abstractMongoFilter._import(method);

            dbCursorWrapper.append("    @Override\n");
            dbCursorWrapper.append("    public " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameters(method) + ") {\n");
            dbCursorWrapper.append("        if ( null==this.filterChain ) {\n");
            dbCursorWrapper.append("            " + _return(method) + "super." + method.getName() + "(" + args(method) + ");\n");
            dbCursorWrapper.append("        } else {\n");
            dbCursorWrapper.append("            " + _return(method) + "filterChain.dbCursor_" + method.getName() + "(this.dbCursor " + args_2(method) + ");\n");
            dbCursorWrapper.append("        }\n");
            dbCursorWrapper.append("    }\n\n");

            // filterChain
            filterChain.append("    " + method.getReturnType().getSimpleName() + " dbCursor_" + method.getName() + "(DBCursor dbCursor " + parameters_2(method) + ");\n\n");

            // mongoFilterChainImpl
            filterChainImpl.append("    @Override\n    ");
            filterChainImpl.append("    public synchronized " + method.getReturnType().getSimpleName() + " dbCursor_" + method.getName() + "(DBCursor dbCursor " + parameters_2(method) + ") {\n");
            filterChainImpl.append("        if (this.position < this.getFilters().size()) {\r\n"); //
            filterChainImpl.append("            MongoFilter nextFilter = this.getFilters().get(this.position++);\n");
            filterChainImpl.append("            " + _return(method) + " nextFilter.dbCursor_" + method.getName() + "(this, dbCursor " + args_2(method) + ");\r\n"); //
            filterChainImpl.append("        } else { \n"); //
            filterChainImpl.append("            " + wrapperResult_2(method, "dbCursor"));//
            filterChainImpl.append("        }\n");
            filterChainImpl.append("    }\n\n");

            // mongoFilter
            mongoFilter.append("    " + method.getReturnType().getSimpleName() + " dbCursor_" + method.getName() + "(MongoFilterChain chain, DBCursor dbCursor " + parameters_2(method) + ");\n\n");

            // abstractMongoFilter
            abstractMongoFilter.append("    @Override\n");
            abstractMongoFilter.append("    public " + method.getReturnType().getSimpleName() + " dbCursor_" + method.getName() + "(MongoFilterChain filterChain, DBCursor dbCursor " + parameters_2(method) + ") {\n");
            abstractMongoFilter.append("        " + _return(method) + "filterChain.dbCursor_" + method.getName() + "(dbCursor " + args_2(method) + ");\n");
            abstractMongoFilter.append("    }\n\n");
        }
    }

    private void go_DBCollection() {
        Method[] methods = ReflectUtil.getMethods_2(DBCollection.class);
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            // dbWrapper
            dbCollectionWrapper._import(method);
            filterChain._import(method);
            filterChainImpl._import(method);
            mongoFilter._import(method);
            abstractMongoFilter._import(method);

            dbCollectionWrapper.append("    @Override\n");
            dbCollectionWrapper.append("    public " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameters(method) + ") {\n");
            dbCollectionWrapper.append("        " + _return(method) + "filterChain.dbCollection_" + method.getName() + "(this.dbCollection " + args_2(method) + ");\n");
            dbCollectionWrapper.append("    }\n\n");

            // filterChain
            filterChain.append("    " + method.getReturnType().getSimpleName() + " dbCollection_" + method.getName() + "(DBCollection dbCollection " + parameters_2(method) + ");\n\n");

            // mongoFilterChainImpl
            filterChainImpl.append("    @Override\n    ");
            filterChainImpl.append("    public synchronized " + method.getReturnType().getSimpleName() + " dbCollection_" + method.getName() + "(DBCollection dbCollection " + parameters_2(method) + ") {\n");
            filterChainImpl.append("        if (this.position < this.getFilters().size()) {\r\n"); //
            filterChainImpl.append("            MongoFilter nextFilter = this.getFilters().get(this.position++);\n");
            filterChainImpl.append("            " + _return(method) + " nextFilter.dbCollection_" + method.getName() + "(this, dbCollection " + args_2(method) + ");\r\n"); //
            filterChainImpl.append("        } else { \n"); //
            filterChainImpl.append("            " + wrapperResult_2(method, "dbCollection"));//
            filterChainImpl.append("        }\n");
            filterChainImpl.append("    }\n\n");

            // mongoFilter
            mongoFilter.append("    " + method.getReturnType().getSimpleName() + " dbCollection_" + method.getName() + "(MongoFilterChain chain, DBCollection dbCollection " + parameters_2(method) + ");\n\n");

            // abstractMongoFilter
            abstractMongoFilter.append("    @Override\n");
            abstractMongoFilter.append("    public " + method.getReturnType().getSimpleName() + " dbCollection_" + method.getName() + "(MongoFilterChain filterChain, DBCollection dbCollection " + parameters_2(method) + ") {\n");
            abstractMongoFilter.append("        " + _return(method) + "filterChain.dbCollection_" + method.getName() + "(dbCollection " + args_2(method) + ");\n");
            abstractMongoFilter.append("    }\n\n");
        }
    }

    private void go_MongoDatabase() {
        Method[] methods = ReflectUtil.getMethods_2(MongoDatabase.class);
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            mongoDatabaseWrapper._import(method);
            filterChain._import(method);
            filterChainImpl._import(method);
            mongoFilter._import(method);
            abstractMongoFilter._import(method);

            // dbWrapper
            mongoDatabaseWrapper.append("    @Override\n");
            mongoDatabaseWrapper.append("    public " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameters(method) + ") {\n");
            mongoDatabaseWrapper.append("        " + _return(method) + "filterChain.mongoDatabase_" + method.getName() + "(this.mongoDatabase " + args_2(method) + ");\n");
            mongoDatabaseWrapper.append("    }\n\n");

            // filterChain
            filterChain.append("    " + method.getReturnType().getSimpleName() + " mongoDatabase_" + method.getName() + "(MongoDatabase mongoDatabase " + parameters_2(method) + ");\n\n");

            // mongoFilterChainImpl
            filterChainImpl.append("    @Override\n    ");
            filterChainImpl.append("    public synchronized " + method.getReturnType().getSimpleName() + " mongoDatabase_" + method.getName() + "(MongoDatabase mongoDatabase " + parameters_2(method) + ") {\n");
            filterChainImpl.append("        if (this.position < this.getFilters().size()) {\r\n"); //
            filterChainImpl.append("            MongoFilter nextFilter = this.getFilters().get(this.position++);\n");
            filterChainImpl.append("            " + _return(method) + " nextFilter.mongoDatabase_" + method.getName() + "(this, mongoDatabase " + args_2(method) + ");\r\n"); //
            filterChainImpl.append("        } else { \n"); //
            filterChainImpl.append("            " + wrapperResult_2(method, "mongoDatabase"));//
            filterChainImpl.append("        }\n");
            filterChainImpl.append("    }\n\n");

            // mongoFilter
            mongoFilter.append("    " + method.getReturnType().getSimpleName() + " mongoDatabase_" + method.getName() + "(MongoFilterChain chain, MongoDatabase mongoDatabase " + parameters_2(method) + ");\n\n");

            // abstractMongoFilter
            abstractMongoFilter.append("    @Override\n");
            abstractMongoFilter.append("    public " + method.getReturnType().getSimpleName() + " mongoDatabase_" + method.getName() + "(MongoFilterChain filterChain, MongoDatabase mongoDatabase " + parameters_2(method) + ") {\n");
            abstractMongoFilter.append("        " + _return(method) + "filterChain.mongoDatabase_" + method.getName() + "(mongoDatabase " + args_2(method) + ");\n");
            abstractMongoFilter.append("    }\n\n");
        }
    }

    private void go_DB() {
        Method[] methods = ReflectUtil.getMethods_2(DB.class);
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            dbWrapper._import(method);
            filterChain._import(method);
            filterChainImpl._import(method);
            mongoFilter._import(method);
            abstractMongoFilter._import(method);

            // dbWrapper
            dbWrapper.append("    @Override\n");
            dbWrapper.append("    public " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameters(method) + ") {\n");
            dbWrapper.append("        " + _return(method) + "filterChain.db_" + method.getName() + "(this.db " + args_2(method) + ");\n");
            dbWrapper.append("    }\n\n");

            // filterChain
            filterChain.append("    " + method.getReturnType().getSimpleName() + " db_" + method.getName() + "(DB db " + parameters_2(method) + ");\n\n");

            // mongoFilterChainImpl
            filterChainImpl.append("    @Override\n");
            filterChainImpl.append("    public synchronized " + method.getReturnType().getSimpleName() + " db_" + method.getName() + "(DB db " + parameters_2(method) + ") {\n");
            filterChainImpl.append("        if (this.position < this.getFilters().size()) {\r\n"); //
            filterChainImpl.append("            MongoFilter nextFilter = this.getFilters().get(this.position++);\n");
            filterChainImpl.append("            " + _return(method) + " nextFilter.db_" + method.getName() + "(this, db " + args_2(method) + ");\r\n"); //
            filterChainImpl.append("        } else { \n"); //
            filterChainImpl.append("            " + wrapperResult_2(method, "db"));//
            filterChainImpl.append("        }\n");
            filterChainImpl.append("    }\n\n");

            // mongoFilter
            mongoFilter.append("    " + method.getReturnType().getSimpleName() + " db_" + method.getName() + "(MongoFilterChain chain, DB db " + parameters_2(method) + ");\n\n");

            // abstractMongoFilter
            abstractMongoFilter.append("    @Override\n");
            abstractMongoFilter.append("    public " + method.getReturnType().getSimpleName() + " db_" + method.getName() + "(MongoFilterChain filterChain, DB db " + parameters_2(method) + ") {\n");
            abstractMongoFilter.append("        " + _return(method) + "filterChain.db_" + method.getName() + "(db " + args_2(method) + ");\n");
            abstractMongoFilter.append("    }\n\n");
        }
    }

    private void go_MongoClient() {
        Method[] methods = ReflectUtil.getMethods_2(MongoClient.class);
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            mongoClientWrapper._import(method);
            filterChain._import(method);
            filterChainImpl._import(method);
            mongoFilter._import(method);
            abstractMongoFilter._import(method);

            // mongoClientWrapper
            mongoClientWrapper.append("    @Override\n");
            mongoClientWrapper.append("    public " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameters(method) + ") {\n");
            mongoClientWrapper.append("        " + _return(method) + "filterChain.mongoClient_" + method.getName() + "(this.mongoClient " + args_2(method) + ");\n");
            mongoClientWrapper.append("    }\n\n");

            // mongoFilterChain
            filterChain.append("    " + method.getReturnType().getSimpleName() + " mongoClient_" + method.getName() + "(MongoClient mongoClient " + parameters_2(method) + ");\n\n");

            // mongoFilterChainImpl
            filterChainImpl.append("    @Override\n");
            filterChainImpl.append("    public synchronized " + method.getReturnType().getSimpleName() + " mongoClient_" + method.getName() + "(MongoClient mongoClient " + parameters_2(method) + ") {\n");
            filterChainImpl.append("        if (this.position < this.getFilters().size()) {\r\n"); //
            filterChainImpl.append("            MongoFilter nextFilter = this.getFilters().get(this.position++);\n");
            filterChainImpl.append("            " + _return(method) + " nextFilter.mongoClient_" + method.getName() + "(this, mongoClient " + args_2(method) + ");\r\n"); //
            filterChainImpl.append("        } else { \n"); //
            filterChainImpl.append("            " + wrapperResult_2(method, "mongoClient"));//
            filterChainImpl.append("        }\n");
            filterChainImpl.append("    }\n\n");

            // mongoFilter
            mongoFilter.append("    " + method.getReturnType().getSimpleName() + " mongoClient_" + method.getName() + "(MongoFilterChain chain, MongoClient mongoClient " + parameters_2(method) + ");\n\n");

            // abstractMongoFilter
            abstractMongoFilter.append("    @Override\n");
            abstractMongoFilter.append("    public " + method.getReturnType().getSimpleName() + " mongoClient_" + method.getName() + "(MongoFilterChain filterChain, MongoClient mongoClient " + parameters_2(method) + ") {\n");
            abstractMongoFilter.append("        " + _return(method) + "filterChain.mongoClient_" + method.getName() + "(mongoClient " + args_2(method) + ");\n");
            abstractMongoFilter.append("    }\n\n");
        }
    }
}